package br.com.sovi.mobile.j2me.stream;

import br.com.sovi.mobile.j2me.stream.impl.NullStreamListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.ConnectionNotFoundException;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

/**
 *
 * @author Joao Galli
 */
public abstract class AbstractStream extends Thread {

    protected String servletURL = null;
    protected boolean verificaToken = false;
    private HttpConnection conn = null;
    private InputStream hdin = null;
    private OutputStream hdout = null;
    private StreamListener listener = new NullStreamListener();

    public AbstractStream(StreamListener listener) {
        if (listener != null) {
            this.listener = listener;
        }
    }

    protected abstract void buildOutputStream(OutputStream hdout) throws Exception;

    protected abstract void parseInputStream(InputStream hdin) throws IOException;

    public abstract String getServletURL();

    protected void connect() {
        listener.start();

        String exceptionMessage = null;

        Throwable throwable = null;
        try {
            conn = (HttpConnection) Connector.open(getServletURL(), Connector.READ_WRITE);
            conn.setRequestMethod(HttpConnection.POST);
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            { // enviando dados para o servidor
                hdout = conn.openOutputStream();
                if (hdout != null) {
                    buildOutputStream(hdout);
                }
                //hdout.flush();
                hdout.close();
            }

            // verificando se o token do celular foi aceito
            if (conn.getResponseCode() == HttpConnection.HTTP_FORBIDDEN) {
                throw new IllegalArgumentException(conn.getResponseMessage());
            }

            // timeout
            if (conn.getResponseCode() == HttpConnection.HTTP_CLIENT_TIMEOUT || conn.getResponseCode() == HttpConnection.HTTP_GATEWAY_TIMEOUT) {
                throw new IllegalArgumentException(
                        "O servidor CardCell não está respondendo!");
            }

            { // recebendo dados do servidor
                hdin = conn.openInputStream();
                if (hdin != null) {
                    parseInputStream(hdin);
                } else {
                    throw new IllegalArgumentException(
                            "Erro na conexão, tente novamente!");
                }
                hdin.close();
            }
        } catch (OutOfMemoryError oome) {
             oome.printStackTrace();
            throwable = oome;
            exceptionMessage = "Erro no aplicativo: Memória insuficiente!";
        } catch (ConnectionNotFoundException cnfe) {
             cnfe.printStackTrace();
            throwable = cnfe;
            exceptionMessage = "Erro de conexão: Conexão não encontrada!";
        } catch (IllegalArgumentException iae) {
             iae.printStackTrace();
             throwable = iae;
            exceptionMessage = iae.getMessage();
        } catch (Exception ex) {
            ex.printStackTrace();
            throwable = ex;
            exceptionMessage = "Erro na Consulta, tente mais tarde!";
        } finally {
            try {
                // fechando a conexao
                if (conn != null) {
                    conn.close();
                }
            } catch (Exception ioe) {
                exceptionMessage = "Erro na aplicação: Não foi possível encerrar a conexão!";
                ioe.printStackTrace();
            }
            
            if (exceptionMessage != null) {
                listener.onError(exceptionMessage, throwable);
            } else {
                listener.success();
            }
        }
    }

    public void run() {
        if (getServletURL() == null) {
            listener.onError("Não é possível conectar: URL inexistente.", null);
        } else {
            try {
                connect();
            } catch (Throwable t) {
                listener.onError("", t);
            }
        }
    }
}
